package seismosurfer.servlets;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import seismosurfer.data.constants.ParameterNames;
import seismosurfer.data.constants.QueryNames;
import seismosurfer.database.CatalogDAO;
import seismosurfer.database.MinMaxDAO;
import seismosurfer.database.QueryDAO;
import seismosurfer.servlets.security.SecurityUtil;
import seismosurfer.servlets.util.ServletUtil;
import seismosurfer.util.Registry;
import seismosurfer.util.SeismoException;

/**
 * This servlet accepts various queries from the applet
 * and sends results using HTTP and object serialization.
 *
 */
public class QueryServlet extends HttpServlet implements ParameterNames,
        QueryNames {
    
    private static final long serialVersionUID = 935148621958274647L;

    // Initialize global variables
    public void init() throws ServletException {

    }

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doPost(request, response);
    }

    // Process the HTTP Post request
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        String queryName = "";
        Map parameters = new HashMap();

        // Read query name and parameters from client
        try {

            ObjectInputStream in = new ObjectInputStream(request
                    .getInputStream());

            try {

                Object obj = in.readObject();

                if (obj instanceof String) {
                    queryName = (String) obj;
                    System.out.println("queryName :" + queryName);
                } else {
                    // Debug.error("Request is not in the expected form.");
                    throw new SeismoException(
                            "Request is not in the expected form.");
                }

                obj = in.readObject();

                if (obj instanceof Map) {
                    parameters = (Map) obj;
                } else if (obj == null) {
                    parameters = null;
                } else {
                    // Debug.error("Request is not in the expected form.");
                    throw new SeismoException(
                            "Request is not in the expected form.");
                }

            } catch (ClassNotFoundException e) {
                // Debug.error(e.getMessage());
                throw new SeismoException(e);
            }

            in.close();
        } catch (IOException e) {
            // Debug.error(e.getMessage());
            throw new SeismoException(e);
        }

        if (queryName.trim().equals("")) {
            // Debug.error("Request is not in the expected form.");
            throw new SeismoException("Request is not in the expected form.");
        }

        else if (queryName.equalsIgnoreCase(CONSTRAINTS)) {
            sendConstraintsResults(request, response);
        } else if (queryName.equalsIgnoreCase(MINMAX)) {
            sendMinMaxResults(response);
        } else if (queryName.equalsIgnoreCase(CATALOG_SOURCES)) {
            sendCatalogSources(response);
        } else if (queryName.equalsIgnoreCase(CATALOGS)) {
            sendCatalogs(response);
        } else if ((queryName.equalsIgnoreCase(MAG_FREQ))
                || (queryName.equalsIgnoreCase(DEPTH_FREQ))) {
            sendFrequencies(response, queryName, parameters);
        } else {
            sendQueryResults(request, response, queryName, parameters);
        }

    }
    
    /**
     * Sends a list of the data sources to the applet.
     * 
     * @param response the HttpServletResponse is used to
     *        send the result 
     */
    protected void sendCatalogSources(HttpServletResponse response) {
        List result = new ArrayList(Registry.getSourceNames());
        ServletUtil.sendBinaryResponse(response, result);
    }
    
    /**
     * Sends a list of catalog data to the applet.
     * 
     * @param response the HttpServletResponse is used to
     *        send the result
     */
    protected void sendCatalogs(HttpServletResponse response) {

        CatalogDAO catDAO = new CatalogDAO();
        List catalogs = catDAO.getCatalogs();

        ServletUtil.sendBinaryResponse(response, catalogs);
    }
    
    /**
     * Sends a Map with the frequencies of the values
     * of magnitude or depths to the applet.
     * 
     * @param response the HttpServletResponse is used to
     *        send the result
     * @param queryName the String that holds the name of the query
     * @param parameters a Map with the name/value pairs of the query 
     *        parameters
     */
    protected void sendFrequencies(
            HttpServletResponse response,
            String queryName, 
            Map parameters) 
    {

        QueryDAO qDB = new QueryDAO();

        Map qResults = qDB.getFrequencies(((String) parameters.get(SOURCE)),
                queryName);

        ServletUtil.sendBinaryResponse(response, qResults);
    }
    
    /**
     * Sends the result of a query to the applet as a List.
     * 
     * @param request the HttpServletRequest is used for
     *        authorization
     * @param response the HttpServletResponse is used to
     *        send the result
     * @param queryName the String that holds the name of the query
     * @param parameters a Map with the name/value pairs of query 
     *        parameters
     */
    protected void sendQueryResults(
            HttpServletRequest request,
            HttpServletResponse response, 
            String queryName, 
            Map parameters) 
    {

        QueryDAO qDB = new QueryDAO();

        // Get query results
        List qResults = null;

        if (queryName.equalsIgnoreCase(MAG)) {
            qResults = qDB.getMagResults(((Long) parameters.get(QUAKEID))
                    .longValue());
        } else if (queryName.equalsIgnoreCase(MACRO)) {            
            qResults = qDB.getMacroResults(((Long) parameters.get(QUAKEID))
                    .longValue());
        } else if (queryName.equalsIgnoreCase(SITES)) {

            // Set Max Rows - The maximum number of rows that a ResultSet object
            // can obtain
            int maxRows = SecurityUtil.getMaxRows(request);

            System.out.println("Sites: " + maxRows);            
            qResults = qDB.getSiteResults(parameters, maxRows);

        } else {
            // Set Max Rows - The maximum number of rows that a ResultSet object
            // can obtain
            int maxRows = SecurityUtil.getMaxRows(request);

            // Get query results            
            qResults = qDB.getQuakeResults(queryName, parameters, maxRows);
        }

        ServletUtil.sendBinaryResponse(response, qResults);
    }
    
    /**
     * Sends a list of the constraints for the applet GUI 
     * components.
     * 
     * @param request the HttpServletRequest will be used for 
     *        the authorization to determine the appropriate 
     *        constraints
     * @param response the HttpServletResponse object 
     *        that will be used to send the data
     */
    protected void sendConstraintsResults(HttpServletRequest request,
            HttpServletResponse response) {

        List constraints = SecurityUtil.getConstraints(request);

        ServletUtil.sendBinaryResponse(response, constraints);

    }
    
    /**
     * Sends min/max data of various db columns
     * to the applet.
     * 
     * @param response the HttpServletResponse object 
     *        that will be used to send the data
     */
    protected void sendMinMaxResults(HttpServletResponse response) {

        MinMaxDAO minMaxData = new MinMaxDAO();
        Map minMaxValues = minMaxData.getMinMaxValues();

        ServletUtil.sendBinaryResponse(response, minMaxValues);
    }

    // Clean up resources
    public void destroy() {

    }

}
